﻿using AutoMapper;
using HamcoWcs.Contract.ContractCommon;
using HamcoWcs.Contract.ContractPcon;
using HamcoWcs.Contract.ContractSrm;
using HamcoWcs.DAL;
using HamcoWcs.Entitys.NodeInfos;
using HamcoWcs.Entitys.SubTasks;
using HamcoWcs.Models.Common;
using HamcoWcs.Models.Common.Enums;
using HamcoWcs.Models.Devices;
using HamcoWcs.Models.Exceptions;
using HamcoWcs.Models.ForeEndModels.UITasks;
using HamcoWcs.Models.MainTasks;
using HamcoWcs.Models.NodeInfos;
using HamcoWcs.Models.WcsLocations;
using HamcoWcs.Service.Common;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using static System.Collections.Specialized.BitVector32;

namespace HamcoWcs.Service.Srm.SrmTaskFinders
{
    [AutoInject(typeof(ISrmTaskFinder), InjectType.Scope)]
    public abstract class SrmTaskFinderBase : ISrmTaskFinder
    {
        protected readonly WcsDbContext _wcsDbContext;
        protected readonly IMapper _mapper;
        protected readonly IBaseConfigService _config;
        protected readonly IPathService _pathService;
        protected readonly IPconBaseService _pconBaseService;
        protected readonly IBaseSrmTaskService _srmTaskService;
        protected readonly ILocationService _locationService;
        protected readonly AutomaticStorageInfo _asrs;

        public abstract string Policy { get; }

        protected SrmTaskFinderBase(WcsDbContext wcsDbContext, IMapper mapper, IBaseConfigService config, IPathService pathService, IPconBaseService pconBaseService, IBaseSrmTaskService srmTaskService, ILocationService locationService, AutomaticStorageInfo asrs)
        {
            _wcsDbContext = wcsDbContext;
            _mapper = mapper;
            _config = config;
            _pathService = pathService;
            _pconBaseService = pconBaseService;
            _srmTaskService = srmTaskService;
            _locationService = locationService;
            _asrs = asrs;
        }


        /// <summary>
        /// 获取丢失的任务，堆垛机无任务有货情况
        /// </summary>
        /// <param name="srm"></param>
        /// <returns></returns>
        protected virtual SubTask GetMissingTask(SrmDto srm)
        {
            var task = _wcsDbContext.SubTasks
                                .AsNoTracking()
                                .Include(x => x.MainTask)
                                .Where(x => x.PlcName == srm.SrmName)
                                .Where(x => x.TaskStatus == EnumSubTaskStatus.OnProgress.ToString())
                                .Where(x => x.MainTask.TaskStatus == EnumMainTaskStatus.OnProgress.ToString())
                                //.Where(x => x.UnitId == srm.UnitId 
                                //&& x.PlcName == srm.SrmName 
                                //&& x.TaskStatus == EnumSubTaskStatus.OnProgress.ToString())
                                .FirstOrDefault();
            return task;
            //return _wcsDbContext.SubTasks
            //                    .AsNoTracking()
            //                    .Include(x => x.MainTask)
            //                    .Where(x => x.PlcName == srm.SrmName)
            //                    .Where(x => x.MainTask.TaskStatus == EnumMainTaskStatus.OnProgress.ToString())
            //                    //.Where(x => x.UnitId == srm.UnitId 
            //                    //&& x.PlcName == srm.SrmName 
            //                    //&& x.TaskStatus == EnumSubTaskStatus.OnProgress.ToString())
            //                    .Where(x => x.PlcName == srm.SrmName
            //                    && x.TaskStatus == EnumSubTaskStatus.OnProgress.ToString())
            //                    .FirstOrDefault();
        }

        /// <summary>
        /// 获取进行中的任务，堆垛机无任务，但是WCS有对应的任务
        /// </summary>
        /// <param name="srm"></param>
        /// <returns></returns>
        protected virtual SubTask GetOnProgressTask(SrmDto srm)
        {
            return _wcsDbContext.SubTasks
                                .AsNoTracking()
                                .Where(x => x.PlcName == srm.SrmName)
                                .Where(x => x.TaskStatus == EnumSubTaskStatus.OnProgress.ToString())
                                .Include(x => x.MainTask)
                                .FirstOrDefault();
        }


        /// <summary>
        /// 检查堆垛机是否有干涉<br/>
        /// true:干涉，false:不干涉<br/>
        /// 默认配置为检查干涉，有任务就下发<br/>
        /// List->110<br/>
        /// 顺序执行，不判断堆垛机是否干涉<br/>
        /// 使用时需要注意，存在安全隐患，请勿随意修改
        /// </summary>
        protected virtual bool CheckInterfere(SubTask task)
        {
            var srm = _asrs.Srms.FirstOrDefault(x => x.SrmName == task.PlcName);
            if (srm is null) return false;

            if (srm.AnotherSrm.IsTask == 0) return false;

            var b = GetTargetBay(task.ToLoc);
            var ab = srm.AnotherSrm.DestinationBay;

            if (!(srm.AnotherSrm.DeviceMode == 1 || srm.AnotherSrm.DeviceMode == 6))
            {
                ab = srm.AnotherSrm.CurrentBay;
            }
            return srm.PortName == "C1" ? (b < ab) : (b > ab);
        }


        protected int GetTargetBay(string t)
        {
            if (t.IsShelf())
            {
                var a = t.Substring(2, 3);
                return int.Parse(a);
            }
            else
            {
                var s = _wcsDbContext.WcsLocations.FirstOrDefault(x => x.WmsLocName == t);
                return s.Bay;
            }
        }

        // todo 堆垛机锁定后需要新增字段判断货架是否无法到达
        protected virtual bool IsTaskCanDo(SubTask task)
        {
            //return true;
            // todo 暂时关闭干涉判断
            //var isInterfere = CheckInterfere(task);
            //if (isInterfere) return false;

            // 宕机切换方向
            if (GlobalValue.ErrorFlag1)
            {

            }

            if (GlobalValue.ErrorFlag2)
            {
                //var vcv700 = _asrs.Pcons.FirstOrDefault(x => x.MachineName == "CJVCV700" && x.PortName == "01");

                //if (task.ToLoc == "CJVCV700" && vcv700)
                //{

                //}
            }

            if (task.ToLoc == "CJVCV300")
            {
                var s = _config.GetConfigValue("CJVCV300TRANSPORTSTATE");
                if (s == "1")
                {
                    var countStr = _config.GetConfigValue("CURRENTCJVCV300TRANSPORTCOUNT");
                    var thresholdStr = _config.GetConfigValue("CJVCV300TRANSPORTTHRESHOLD");
                    int count = int.Parse(countStr);
                    int threshold = int.Parse(thresholdStr);

                    if (count >= threshold)
                    {
                        return false;
                    }

                    var pcon = _asrs.Pcons.FirstOrDefault(x => x.MachineName == "CJVCV300" && x.PortName == "01");

                    if (task.FromLoc == "CJSTW200")
                    {
                        if (pcon.WorkType != 2) return false;
                    }
                    else
                    {
                        if (pcon.WorkType != 1) return false;
                    }
                }
            }

            if (task.SubTaskType == EnumSubTaskType.SrmOutTask.ToString())
            {
                //出库任务，检查出库站台
                var station = GetPcon(task.ToLoc);

                NodeInfo node = null;

                if (station == null || station.WorkType == 1 || station.IsGoods == 1 || (!station.Machine.IsRunning || station.PconMode == 2))
                {
                    return false;
                }


                if (station.MachineName == "CJVCV100" || station.MachineName == "CJVCV200")
                {
                    var stask = _wcsDbContext.SubTasks
                        .FirstOrDefault(x => x.ToLoc == station.MachineName && x.TaskStatus == EnumSubTaskStatus.OnProgress.ToString());

                    if (stask == null) return true;
                    if (stask.UnitId == task.UnitId) return true;

                    return false;
                }

                //if (station != null && (station.MachineName == "CJVCV100" || station.MachineName == "CJVCV200"))
                //{
                //    node.NodeMode = 1;
                //    _wcsDbContext.SaveChanges();
                //}
            }
            else if (task.SubTaskType == EnumSubTaskType.SrmInTask.ToString())
            {
                //入库任务，检查入库站台
                var station = GetPcon(task.FromLoc);
                if (station == null || !(station.PconMode == 1 || station.PconMode == 6 || station.PconMode == 7) || station.IsGoods == 0 || station.UnitId != task.UnitId)
                {
                    return false;
                }
            }
            else if (task.SubTaskType == EnumSubTaskType.SrmStraightOutTask.ToString())
            {
                //直出任务，检查入库站台与出库站台
                var fstation = GetPcon(task.FromLoc);

                if (fstation == null || !(fstation.PconMode == 1 || fstation.PconMode == 6 || fstation.PconMode == 7) || fstation.IsGoods == 0 || fstation.UnitId != task.UnitId)
                {
                    return false;
                }

                var tstation = GetPcon(task.ToLoc);

                NodeInfo tnode = null;
                //if (tstation.MachineName == "CJVCV100" || tstation.MachineName == "CJVCV200")
                //{
                //    tnode = _wcsDbContext.NodeInfos.FirstOrDefault(x => x.NodeName == tstation.MachineName);
                //    // 已经预约
                //    if (tnode?.NodeMode == 1)
                //    {
                //        return false;
                //    }
                //}

                if (tstation == null || tstation.IsGoods == 1 || !(fstation.PconMode == 1 || fstation.PconMode == 6 || fstation.PconMode == 7))
                {
                    return false;
                }

                if (tstation.MachineName == "CJVCV100" || tstation.MachineName == "CJVCV200")
                {
                    var stask = _wcsDbContext.SubTasks
                        .FirstOrDefault(x => x.ToLoc == tstation.MachineName && x.TaskStatus == EnumSubTaskStatus.OnProgress.ToString());

                    if (stask == null) return true;
                    if (stask.UnitId == task.UnitId) return true;

                    return false;
                }
                //if (tnode != null)
                //{
                //    tnode.NodeMode = 1;
                //    _wcsDbContext.SaveChanges();
                //}
            }
            return true;

        }

        protected virtual SrmPlc GetExcutePlc(NodeInfoDto aisle, SubTask subTask)
        {


            return null;
        }

        protected virtual PconDto GetPcon(string srmstation)
        {
            //var station
            var pconName = _locationService.GetPconNameByWmsLocationName(srmstation);
            if (pconName == 0) return null;
            return _asrs.Pcons.FirstOrDefault(x => x.PconName == pconName);


            //var node = _pathService.GetSrmNode(srmstation);
            //if (node == null)
            //    node = _pathService.GetWcsNode(srmstation);
            //if (node == null)
            //    return null;
            //var pconplc = _pconBaseService.GetPconPlc(node.PlcName);
            //if (!pconplc.Pcons.ContainsKey(int.Parse(node.NodeName)))
            //    return null;
            //return pconplc.Pcons[int.Parse(node.NodeName)];
        }

        //public abstract SubTask Find(NodeInfoDto aisle);


        public void PickSrm(NodeInfoDto aisle)
        {
            // 巷道无可用堆垛机时不执行
            if (aisle.AisleMode == EnumSrmAisleMode.BeforeInit
                || aisle.AisleMode == EnumSrmAisleMode.AllDisable)
                return;

            var subTasks = _wcsDbContext.SubTasks
                .Where(x => x.TaskStatus == EnumSubTaskStatus.Ready.ToString())
                .Where(x => x.PlcName == aisle.NodeName)
                .Include(x => x.MainTask)
                .Where(x => x.MainTask.TaskStatus == EnumMainTaskStatus.Ready.ToString()
                || x.MainTask.TaskStatus == EnumMainTaskStatus.OnProgress.ToString())
                .ToList();


            foreach (var subTask in subTasks)
            {
                // 设置MainTask扩展信息
                try
                {
                    if (aisle.AisleMode == EnumSrmAisleMode.Normal)
                    {
                        HandleTwoSrmTask(aisle, subTask);
                    }
                    else if (aisle.AisleMode == EnumSrmAisleMode.OneDisable)
                    {
                        HandleOneSrmTask(aisle, subTask);
                    }
                }
                catch (SectionException)
                {
                    continue;
                }
                catch (Exception ex)
                {
                    Debug.Assert(false);
                    subTask.MainTask.TaskStatus = EnumMainTaskStatus.Error.ToString();
                    continue;
                }
            }

            _wcsDbContext.SaveChanges();
        }



        private static void HandleOneSrmTask(NodeInfoDto aisle, SubTask subTask)
        {
            var srm = aisle.GetEnabledSrm();
            subTask.PlcName = srm.SrmName;
            subTask.IsNeedSection = false;
        }


        public WcsLocationDto GetLocationByWmsName(string wmsName, string aisle)
        {
            var loc = _wcsDbContext.WcsLocations
                                   .AsNoTracking()
                                   .Where(x => x.WmsLocName == wmsName)
                                   .Where(x => x.Aisle == aisle)
                                   .FirstOrDefault();
            if (loc == null)
            {
                loc = _wcsDbContext.WcsLocations
                                    .AsNoTracking()
                                    .Where(x => x.WcsLocName == wmsName)
                                    .Where(x => x.Aisle == aisle)
                                    .FirstOrDefault();
            }

            return _mapper.Map<WcsLocationDto>(loc);
        }





        private void HandleTwoSrmTask(NodeInfoDto aisle, SubTask subTask)
        {
            if (string.IsNullOrEmpty(subTask.FromLoc) && subTask.SubTaskType != EnumSubTaskType.SrmInventoryTask.ToString())
            {
                var loc = _locationService.GetPalletLocation(subTask.UnitId);
                subTask.FromLoc = loc.WcsLocName;
            }

            if (subTask.SubTaskType == EnumSubTaskType.SrmInventoryTask.ToString())
            {
                var tloc = GetLocationByWmsName(subTask.ToLoc, subTask.PlcName);
                var srm = aisle.GetInventorySrm(tloc.WcsZone);
                subTask.PlcName = srm.SrmName;
            }
            else
            {
                //bool isEmptyMiddleLocation = 
                var isSection = _locationService.CheckIsNeedSection(subTask.FromLoc, subTask.ToLoc, subTask.PlcName, out WcsLocationDto floc, out WcsLocationDto tloc);
                //subTask.IsNeedSection = isSection;
                if (isSection)
                {
                    var midLoc = _locationService.GetMiddleLocation(subTask.PlcName);

                    if (midLoc is null)
                        return;

                    if (midLoc.ZoneName.Contains("Z6"))
                    {
                        midLoc.LocStatus = (int)EnumLocStatus.In;
                    }
                    else
                    {
                        midLoc.LocStatus = (int)EnumLocStatus.TempHandOff;
                    }
                    midLoc.Remark = $"{subTask.UnitId}中转";
                    if (subTask.FromLoc.IsShelf())
                    {
                        subTask.SubTaskType = EnumSubTaskType.SrmMoveTask.ToString();
                    }

                    subTask.HandOffShelf = midLoc.WcsLocName;
                    subTask.IsNeedSection = true;
                    _wcsDbContext.SaveChanges();
                }

                var excuteSrm = aisle.GetExcuteSrm(floc.WcsZone, tloc.WcsZone);
                subTask.PlcName = excuteSrm.SrmName;
            }



        }

        public abstract SubTask Find(SrmDto srm);
    }
}
